package com.example.ruoyivoicecall.controller;

import com.example.ruoyivoicecall.util.FfmpegUtil;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.example.ruoyivoicecall.util.EncodingUtil;

import static com.example.ruoyivoicecall.common.VoiceUnitUtil.ConvertStreamToString;

@Controller
@RequestMapping("/inter")
public class InterController {

    @Value("${voice.call.settings.bcall_batch}")
    private String bcallBatch;

    @Value("${voice.call.settings.code_area}")
    private String codeArea;

    @Value("${voice.call.settings.code_area2}")
    private String codeArea2;

    @Value("${voice.call.settings.code_area3}")
    private String codeArea3;

    @Value("${voice.call.settings.phone_calloutb}")
    private String phoneCalloutb;

    @Value("${voice.call.settings.voiceDistDir}")
    private String voiceDistDir;

    @Value("${voice.call.settings.voiceUploadDir}")
    private String voiceUploadDir;

    @Value("${voice.call.settings.sysId}")
    private String sysId;

    @Value("${voice.call.settings.username}")
    private String username;

    @Value("${voice.call.settings.password}")
    private String password;

    @Value("${voice.call.settings.serverUrl}")
    private String serverUrl;

    @Value("${voice.call.settings.voiceUrlPrefix}")
    private String voiceUrlPrefix;

    @Value("${voice.call.settings.ffmpegPath}")
    private String ffmpegPath;
    
    @Autowired
    private FfmpegUtil ffmpegUtil;

    /**
     * 第一步：上传wav文件准备播放语音
     * @param file
     * @return
     */
    /**
     * 获取外呼流水记录
     * @param phones 外呼号码，多个用英文逗号分隔
     * @return JSON字符串，包含查询到的外呼流水记录
     */
    @GetMapping("/getVoiceCallRecord")
    @ResponseBody
    public String getVoiceCallRecord(@RequestParam("phones") String phones) {
        if (phones == null || phones.trim().isEmpty()) {
            return "{\"status\":1,\"msg\":\"" + EncodingUtil.native2Ascii("phones不能为空") + "\"}";
        }
        // 0. 请求 /v/start 页面，抓取 sysId
        try (org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient =
                     org.apache.hc.client5.http.impl.classic.HttpClients.createDefault()) {

            HttpGet startGet = new HttpGet(serverUrl + "/v/start");
            String startHtml;
            try (CloseableHttpResponse resp = httpClient.execute(startGet)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":1,\"msg\":\"获取前置信息失败，状态码：" + resp.getCode() + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                startHtml = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }

            Document doc = Jsoup.parse(startHtml);
            Element sysIdInput = doc.selectFirst("input[name=sysId]");
            if (sysIdInput == null) {
                return "{\"status\":2,\"msg\":\"前置信息查找失败\"}";
            }
            String freshSysId = sysIdInput.val();
            // 用抓取到的值覆盖原有sysId
            sysId = freshSysId;
        } catch (Exception e) {
            return "{\"status\":3,\"msg\":\"抓取sysId异常：" + e.getMessage() + "\"}";
        }
        // 1. 登录外呼系统
        try (org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient = 
                org.apache.hc.client5.http.impl.classic.HttpClients.createDefault()) {
            
            // 登录请求
            HttpPost loginPost = new HttpPost(serverUrl + "/v/logon");
            loginPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            List<NameValuePair> loginParams = new ArrayList<>();
            loginParams.add(new BasicNameValuePair("sysId", sysId));
            loginParams.add(new BasicNameValuePair("id_area", codeArea));
            loginParams.add(new BasicNameValuePair("j_username", username));
            loginParams.add(new BasicNameValuePair("j_password", password));
            loginParams.add(new BasicNameValuePair("vo_id", "login"));
            loginPost.setEntity(new UrlEncodedFormEntity(loginParams));

            String loginResp;
            try (CloseableHttpResponse resp = httpClient.execute(loginPost)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":2,\"msg\":\"" + EncodingUtil.native2Ascii("登录请求失败，状态码：" + resp.getCode()) + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                loginResp = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }

            if (!loginResp.contains("frameset")) {
                return "{\"status\":3,\"msg\":\"" + EncodingUtil.native2Ascii("登录失败，用户名或密码错误") + "\"}";
            }

            // 2. 按手机号查询记录
            String[] phoneArray = phones.split(",");
            StringBuilder jsonArrayBuilder = new StringBuilder();
            jsonArrayBuilder.append("[");

            // 计算时间范围（默认查询最近7天）
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMdd");
            java.util.Calendar cal = java.util.Calendar.getInstance();
//            String endDate = sdf.format(cal.getTime());
            cal.add(java.util.Calendar.DAY_OF_YEAR, 1);
            String endDate = sdf.format(cal.getTime());
            cal.add(java.util.Calendar.DAY_OF_YEAR, -8);
            String startDate = sdf.format(cal.getTime());

            for (int i = 0; i < phoneArray.length; i++) {
                String phone = phoneArray[i].trim();
                if (phone.isEmpty()) continue;

                // 构建查询请求
                HttpPost queryPost = new HttpPost(serverUrl + "/v/queryAck");
                queryPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=GBK");
                queryPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

                List<NameValuePair> queryParams = new ArrayList<>();
                queryParams.add(new BasicNameValuePair("date_simple_start", startDate));
                queryParams.add(new BasicNameValuePair("date_simple_end", endDate));
                queryParams.add(new BasicNameValuePair("ser_no", "")); // 流水号留空
                queryParams.add(new BasicNameValuePair("phone_cust", phone));
//                queryParams.add(new BasicNameValuePair("code_operator", username));
                queryParams.add(new BasicNameValuePair("code_direction", "8")); // 呼叫类型默认8
                queryParams.add(new BasicNameValuePair("code_voice_type", "%")); // 语音类型留空
                // 添加其他必要参数
                queryParams.add(new BasicNameValuePair("cust_id", ""));
                queryParams.add(new BasicNameValuePair("dtmf", ""));
                queryParams.add(new BasicNameValuePair("ch", ""));
                queryParams.add(new BasicNameValuePair("code_satis", "%"));
                queryParams.add(new BasicNameValuePair("memo", ""));

//                queryParams.add(new BasicNameValuePair("pageSize", "10"));
//                queryParams.add(new BasicNameValuePair("pageNo", "1"));
//                queryParams.add(new BasicNameValuePair("query_id", ""));
//                queryParams.add(new BasicNameValuePair("_idaction_", "6"));
//                queryParams.add(new BasicNameValuePair("repType", "ackjsp"));
//                queryParams.add(new BasicNameValuePair("ackjsp", "/jsp/call_query.jsp"));
//                queryParams.add(new BasicNameValuePair("vtype", "BPara"));
//                queryParams.add(new BasicNameValuePair("callQueryForm", "callQueryForm"));
                queryParams.add(new BasicNameValuePair("code_time_start", "%"));
                queryParams.add(new BasicNameValuePair("code_time_end", "%"));
                queryParams.add(new BasicNameValuePair("ifNeedNoSplit", "true"));
                queryParams.add(new BasicNameValuePair("_nolock_", "1"));
                queryParams.add(new BasicNameValuePair("useSplitQuery", "true"));
                queryParams.add(new BasicNameValuePair("_totalcnt_", "115"));
                queryParams.add(new BasicNameValuePair("_idaction_", "71"));
                queryParams.add(new BasicNameValuePair("query_id", "5000"));
                queryParams.add(new BasicNameValuePair("_pageID_", ""));
                queryParams.add(new BasicNameValuePair("_pageRows_", ""));
                queryParams.add(new BasicNameValuePair("pn", "1"));
                queryParams.add(new BasicNameValuePair("displayM", ""));
                queryPost.setEntity(new UrlEncodedFormEntity(queryParams));

                String queryResp;
                try (CloseableHttpResponse resp = httpClient.execute(queryPost)) {
                    if (resp.getCode() != 200) {
                        // 记录错误但继续处理其他手机号
                        System.err.println("查询手机号" + phone + "失败，状态码：" + resp.getCode());
                        continue;
                    }
                    HttpEntity entity = resp.getEntity();
                    queryResp = entity != null ? new String(entity.getContent().readAllBytes(), "UTF-8") : "";
                }

                // 解析HTML响应
                Document doc = Jsoup.parse(queryResp);
                Element table = doc.getElementById("datalist1");
                
                if (table != null) {
                    Elements rows = table.select("tr");
                    // 检查是否有数据行（第一行是表头，第二行开始是数据）
                    if (rows.size() > 1) {
                        // 获取第二行数据（最新的记录）
                        Element dataRow = rows.get(1);
                        Elements cells = dataRow.select("td");

                        // 构建JSON对象，对中文字段进行native编码
                        if (cells.size() >= 13) {
                            // 先从单元格获取文本，确保编码正确后再进行native编码
                            String serNo = cells.get(1).text().trim();
                            String customerNo = cells.get(2).text().trim();
                            String contact = cells.get(3).text().trim();
                            String operatorCode = cells.get(4).text().trim();
                            String callType = cells.get(5).text().trim();
                            String phoneNum = cells.get(6).text().trim();
                            String city = cells.get(7).text().trim();
                            String date = cells.get(8).text().trim();
                            String callStartTime = cells.get(9).text().trim();
                            String channel = cells.get(10).text().trim();
                            String status = cells.get(12).text().trim();
                            String voice = cells.get(14).text().trim();
                            String keys = "";//cells.get(14).text().trim();
                            // 使用EncodingUtil.native2Ascii对中文进行ASCII编码
                            String jsonRecord = "{" +
                                "\"phone\":\"" + phone + "\"," +
                                "\"ser_no\":\"" + EncodingUtil.native2Ascii(serNo) + "\"," +
                                "\"customer_no\":\"" + EncodingUtil.native2Ascii(customerNo) + "\"," +
                                "\"contact\":\"" + EncodingUtil.native2Ascii(contact) + "\"," +
                                "\"operator_code\":\"" + EncodingUtil.native2Ascii(operatorCode) + "\"," +
                                "\"call_type\":\"" + EncodingUtil.native2Ascii(callType) + "\"," +
                                "\"phoneNum\":\"" + EncodingUtil.native2Ascii(phoneNum) + "\"," +
                                "\"city\":\"" + EncodingUtil.native2Ascii(city) + "\"," +
                                "\"date\":\"" + EncodingUtil.native2Ascii(date) + "\"," +
                                "\"callStartTime\":\"" + EncodingUtil.native2Ascii(callStartTime) + "\"," +
                                "\"channel\":\"" + EncodingUtil.native2Ascii(channel) + "\"," +
                                "\"status\":\"" + EncodingUtil.native2Ascii(status) + "\"," +
                                "\"voice\":\"" + getVoiceUrl(voice) + "\"," +
//                                "\"keys\":\"" + EncodingUtil.native2Ascii(keys) + "\"" +
                                "}";

                            if (jsonArrayBuilder.length() > 1) {
                                jsonArrayBuilder.append(",");
                            }
                            jsonArrayBuilder.append(jsonRecord);
                            
                            // 打印输出
                            System.out.println("手机号 " + phone + " 的外呼记录：" + jsonRecord);
                        }
                    }
                }
            }

            jsonArrayBuilder.append("]");

            // 返回查询结果，对msg中的中文进行ASCII编码
            return "{\"status\":0,\"msg\":\"" + EncodingUtil.native2Ascii("查询成功") + "\",\"extra\":" + jsonArrayBuilder.toString() + "}";
            
        } catch (Exception e) {
            return "{\"status\":500,\"msg\":\"" + EncodingUtil.native2Ascii("系统异常：" + e.getMessage()) + "\"}";
        }
    }

    private String getVoiceUrl(String voice) {
        if(voice==null || voice.length()<8 || !voice.endsWith(".wav")){
            return voice;
        }
        String prefix=voiceUrlPrefix+"/dvdau/wav/"+voice.substring(0,8)+"/";
        return prefix+voice;
    }

    /**
     * 第一步：上传wav文件准备播放语音
     * @param file
     * @return
     */
    @PostMapping("/uploadVoiceFile")
    public @ResponseBody String uploadVoiceFile(@RequestParam("file") MultipartFile file) {
        try {
            if (file.isEmpty()) {
                return "{\"status\":1,\"msg\":\"上传文件为空\"}";
            }
            if (file.getSize() > 4 * 1024 * 1024) {
                return "{\"status\":2,\"msg\":\"上传文件大小超过4MB限制\"}";
            }
            if (!file.getOriginalFilename().toLowerCase().endsWith(".wav")) {
                return "{\"status\":3,\"msg\":\"仅支持wav格式文件\"}";
            }
            File uploadDir = new File(voiceUploadDir);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }
            String fileName = System.currentTimeMillis() + ".wav";
            File destFile = new File(uploadDir, fileName);
            file.transferTo(destFile);
            
            // 转换上传的文件
            try {
                String convertedFilePath = ffmpegUtil.convertAudioFile(destFile.getAbsolutePath());
                System.out.println("文件转换成功: " + convertedFilePath);
            } catch (Exception e) {
                System.err.println("文件转换失败: " + e.getMessage());
                return "{\"status\":5,\"msg\":\"文件转换失败: " + e.getMessage() + "\"}";
            }
            
            return "{\"status\":0,\"msg\":\"File upload success\",\"fileId\":\"" + fileName.substring(0, fileName.indexOf(".")) + "\"}";
        } catch (Exception e) {
            return "{\"status\":4,\"msg\":\"" + e.getMessage() + "\"}";
        }
    }

    /**
     * 第二步：启动外呼，三方系统 REST API：启动语音外呼
     * @param fileId   文件上传接口返回的 fileId
     * @param phones   外呼号码，多个用英文逗号分隔
     * @return         JSON 字符串，格式与 uploadVoiceFile 保持一致
     */
    @PostMapping("/startVoiceCall")
    @ResponseBody
    public String startVoiceCall(@RequestParam("fileId") String fileId,
                                 @RequestParam("phones") String phones) {
        if (fileId == null || fileId.trim().isEmpty()) {
            return "{\"status\":1,\"msg\":\"fileId不能为空\"}";
        }
        if (phones == null || phones.trim().isEmpty()) {
            return "{\"status\":2,\"msg\":\"phones不能为空\"}";
        }
        // 0. 请求 /v/start 页面，抓取 sysId
        try (org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient =
                     org.apache.hc.client5.http.impl.classic.HttpClients.createDefault()) {

            HttpGet startGet = new HttpGet(serverUrl + "/v/start");
            String startHtml;
            try (CloseableHttpResponse resp = httpClient.execute(startGet)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":1,\"msg\":\"获取前置信息失败，状态码：" + resp.getCode() + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                startHtml = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }

            Document doc = Jsoup.parse(startHtml);
            Element sysIdInput = doc.selectFirst("input[name=sysId]");
            if (sysIdInput == null) {
                return "{\"status\":2,\"msg\":\"前置信息查找失败\"}";
            }
            String freshSysId = sysIdInput.val();
            // 用抓取到的值覆盖原有sysId
            sysId = freshSysId;
        } catch (Exception e) {
            return "{\"status\":3,\"msg\":\"抓取sysId异常：" + e.getMessage() + "\"}";
        }

       
        // 1. 登录外呼系统
        try (org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient =
                     org.apache.hc.client5.http.impl.classic.HttpClients.createDefault()) {

            HttpPost loginPost = new HttpPost(serverUrl + "/v/logon");
            loginPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            List<NameValuePair> loginParams = new ArrayList<>();
            loginParams.add(new BasicNameValuePair("sysId", sysId));
            loginParams.add(new BasicNameValuePair("id_area", codeArea));
            loginParams.add(new BasicNameValuePair("j_username", username));
            loginParams.add(new BasicNameValuePair("j_password", password));
            loginParams.add(new BasicNameValuePair("vo_id", "login"));
            loginPost.setEntity(new UrlEncodedFormEntity(loginParams));

            String loginResp;
            try (CloseableHttpResponse resp = httpClient.execute(loginPost)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":3,\"msg\":\"登录请求失败，状态码：" + resp.getCode() + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                loginResp = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }
//            System.out.println(loginResp);
            if (!loginResp.contains("frameset")) {
                return "{\"status\":4,\"msg\":\"登录失败，用户名或密码错误\"}";
            }
            // 2.查询通道占用情况
            HttpGet channelGet = new HttpGet(serverUrl +
                    "/v/vack?callback=jQuery172009196453624172785_1761718143909&vo_id=getChStatus&type=0&_secs_=lcall&_idaction_=61&_log_=0&monCh=&forward=API&jsonp=callback&_=" + System.currentTimeMillis());
            try (CloseableHttpResponse channelResp = httpClient.execute(channelGet)) {
                if (channelResp.getCode() != 200) {
                    return "{\"status\":14,\"msg\":\"查询通道状态失败，状态码：" + channelResp.getCode() + "\"}";
                }
                HttpEntity chentity = channelResp.getEntity();
                String channelResult = chentity != null ? new String(chentity.getContent().readAllBytes()) : "";
                // 去掉JSONP包装
                int start = channelResult.indexOf('[');
                int end = channelResult.lastIndexOf(']') + 1;
                if (start == -1 || end == 0) {
                    return "{\"status\":15,\"msg\":\"通道状态返回格式异常\"}";
                }
                String json = channelResult.substring(start, end);
                // 简单判断是否有外线通道非空闲
                // 将通道状态字符串解析成 JSON 数组
                try {
                    com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    com.fasterxml.jackson.databind.JsonNode root = mapper.readTree(json);

                    // 遍历通道，判断是否存在占用
                    boolean occupied = false;
                    com.fasterxml.jackson.databind.JsonNode nodes=root.get(0).get("chStatus");
                    // 遍历第一层通道列表
                    for(com.fasterxml.jackson.databind.JsonNode node : nodes) {

                        // ch 本身即为通道对象，直接读取其字段
                        if ("外线".equals(node.get("type").asText())) {
                            String status = node.get("status").asText();
//                                if ("通话中".equals(status) || "振铃".equals(status) || "拨号".equals(status)) {
                            if (!"空闲".equals(status)) {
                                occupied = true;
                                break;
                            }
                        }
                    }


                    if (occupied) {
                        return "{\"status\":16,\"msg\":\"通道占用,请稍后重试\"}";
                    }
                } catch (Exception e) {
                    return "{\"status\":17,\"msg\":\"解析通道状态异常：" + e.getMessage() + "\"}";
                }
            } catch (Exception e) {
                return "{\"status\":17,\"msg\":\"解析通道状态异常：" + e.getMessage() + "\"}";
            }
            // 3. 复制音频文件
            String srcName = fileId + "_converted.wav";
            File srcFile = new File(voiceUploadDir, srcName);
            
            if (!srcFile.exists()) {
                return "{\"status\":5,\"msg\":\"音频文件不存在，fileId=" + fileId + "\"}";
            }
            File destDir = new File(voiceDistDir);
            if (!destDir.exists()) {
                return "{\"status\":6,\"msg\":\"目标文件夹不存在：" + voiceDistDir + "\"}";
            }
            File destFile = new File(destDir, "stateGrid_warning.wav");
            try {
                java.nio.file.Files.copy(srcFile.toPath(), destFile.toPath(),
                        java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                return "{\"status\":7,\"msg\":\"复制音频文件失败：" + e.getMessage() + "\"}";
            }

            // 4. 刷新音频文件
            HttpGet refreshGet = new HttpGet(serverUrl +
                    "/v/vack?vo_id=reloadAllIndexString&vtype=V&repType=xml&_idaction_=21&segNo=0&ifAjax=false");
            try (CloseableHttpResponse refreshResp = httpClient.execute(refreshGet)) {
                if (refreshResp.getCode() != 200) {
                    return "{\"status\":8,\"msg\":\"刷新音频文件请求失败，状态码：" + refreshResp.getCode() + "\"}";
                }
                HttpEntity entity = refreshResp.getEntity();
                String refreshResult = entity != null ? new String(entity.getContent().readAllBytes()) : "";
                if (!refreshResult.contains("执行成功")) {
                    return "{\"status\":9,\"msg\":\"刷新音频文件失败\"}";
                }
            }

            // 5. 添加外呼号码（批量）
            HttpPost batchPost = new HttpPost(serverUrl + "/v/vack");
            batchPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            List<NameValuePair> batchParams = new ArrayList<>();
            batchParams.add(new BasicNameValuePair("phone_calloutb", phones.replaceAll(",", "\n")));
            batchParams.add(new BasicNameValuePair("_secs_", "lcall"));
            batchParams.add(new BasicNameValuePair("vo_id", "ctask_add"));
            batchParams.add(new BasicNameValuePair("repType", "ackjsp"));
            batchParams.add(new BasicNameValuePair("ackjsp", "/jsp/btask_resp.jsp"));
            batchParams.add(new BasicNameValuePair("vtype", "B"));
            batchParams.add(new BasicNameValuePair("bcall_batch", bcallBatch));
            batchParams.add(new BasicNameValuePair("id_bcall", "自动"));
            batchParams.add(new BasicNameValuePair("id_oper", username));
            batchParams.add(new BasicNameValuePair("code_area", codeArea));
            batchParams.add(new BasicNameValuePair("code_area2", codeArea2));
            batchParams.add(new BasicNameValuePair("code_area3", codeArea3));
            batchParams.add(new BasicNameValuePair("_idaction_", "f6"));
            batchPost.setEntity(new UrlEncodedFormEntity(batchParams));

            String batchResp;
            try (CloseableHttpResponse resp = httpClient.execute(batchPost)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":10,\"msg\":\"批量添加号码请求失败，状态码：" + resp.getCode() + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                batchResp = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }
            if (!batchResp.contains("添加成功")) {
                return "{\"status\":11,\"msg\":\"批量添加号码失败\"}";
            }

            // 6. 启动外呼
            HttpPost startPost = new HttpPost(serverUrl + "/v/vack");
            startPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            List<NameValuePair> startParams = new ArrayList<>();
            startParams.add(new BasicNameValuePair("vo_id", "bctask_start"));
            startParams.add(new BasicNameValuePair("bcall_batch", bcallBatch));
            startParams.add(new BasicNameValuePair("vtype", "B"));
            startParams.add(new BasicNameValuePair("repType", "xml"));
            startParams.add(new BasicNameValuePair("ifAjax", "true"));
            startPost.setEntity(new UrlEncodedFormEntity(startParams));

            String startResp;
            try (CloseableHttpResponse resp = httpClient.execute(startPost)) {
                if (resp.getCode() != 200) {
                    return "{\"status\":12,\"msg\":\"启动外呼请求失败，状态码：" + resp.getCode() + "\"}";
                }
                HttpEntity entity = resp.getEntity();
                startResp = entity != null ? new String(entity.getContent().readAllBytes()) : "";
            }

            String rcode = "";
            if (startResp.contains("rcode=\"")) {
                int s = startResp.indexOf("rcode=\"") + 7;
                int e = startResp.indexOf("\"", s);
                rcode = startResp.substring(s, e);
            }
            if (!"0".equals(rcode)) {
                String error = "";
                if (startResp.contains("error=\"")) {
                    int s = startResp.indexOf("error=\"") + 7;
                    int e = startResp.indexOf("\"", s);
                    error = startResp.substring(s, e);
                }
                return "{\"status\":13,\"msg\":\"启动外呼失败，错误信息：" + error + "\"}";
            }

            return "{\"status\":0,\"msg\":\"启动外呼成功\"}";
        } catch (Exception e) {
            return "{\"status\":99,\"msg\":\"系统异常：" + e.getMessage() + "\"}";
        }
    }

    @GetMapping("/test")
    public String test() {

        // 创建HttpClient实例
        try (org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient =
                     org.apache.hc.client5.http.impl.classic.HttpClients.createDefault()) {

            // 创建POST请求
            HttpPost httpPost = new HttpPost(serverUrl+"/v/logon");

            // 设置请求头
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            // 构建请求参数
            List<NameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("sysId", sysId));
            params.add(new BasicNameValuePair("id_area", codeArea));
            params.add(new BasicNameValuePair("j_username", username));
            params.add(new BasicNameValuePair("j_password", password));
            params.add(new BasicNameValuePair("vo_id", "login"));

            // 设置请求实体
            httpPost.setEntity(new UrlEncodedFormEntity(params));

            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                // 检查状态码
                if (response.getCode() != 200) {
                    System.err.println("登录请求失败，状态码：" + response.getCode());
                    return "error";
                }

                // 读取响应内容
                HttpEntity entity = response.getEntity();
                String responseBody;
                if (entity != null) {
                    try (InputStream inputStream = entity.getContent()) {
                        responseBody = new String(inputStream.readAllBytes());
                    }
                } else {
                    responseBody = "";
                }

                // 判断登录是否成功
                if (responseBody.contains("frameset")) {
                    System.out.println("登录成功！");
                    // 输出当前httpClient的变量信息（此处为示例，实际可根据需要输出具体信息）
                    System.out.println("当前登录成功状态下的httpClient实例：" + httpClient);
// 查询通道占用情况
            HttpGet channelGet = new HttpGet(serverUrl +
                    "/v/vack?callback=jQuery172009196453624172785_1761718143909&vo_id=getChStatus&type=0&_secs_=lcall&_idaction_=61&_log_=0&monCh=&forward=API&jsonp=callback&_=" + System.currentTimeMillis());
            try (CloseableHttpResponse channelResp = httpClient.execute(channelGet)) {
                if (channelResp.getCode() != 200) {
                    return "{\"status\":14,\"msg\":\"查询通道状态失败，状态码：" + channelResp.getCode() + "\"}";
                }
                HttpEntity chentity = channelResp.getEntity();
                String channelResult = chentity != null ? new String(chentity.getContent().readAllBytes()) : "";
                // 去掉JSONP包装
                int start = channelResult.indexOf('[');
                int end = channelResult.lastIndexOf(']') + 1;
                if (start == -1 || end == 0) {
                    return "{\"status\":15,\"msg\":\"通道状态返回格式异常\"}";
                }
                String json = channelResult.substring(start, end);
                // 简单判断是否有外线通道非空闲
                // 将通道状态字符串解析成 JSON 数组
                try {
                    com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    com.fasterxml.jackson.databind.JsonNode root = mapper.readTree(json);

                    // 遍历通道，判断是否存在占用
                    boolean occupied = false;
                    com.fasterxml.jackson.databind.JsonNode nodes=root.get(0).get("chStatus");
                        // 遍历第一层通道列表
                        for(com.fasterxml.jackson.databind.JsonNode node : nodes) {

                            // ch 本身即为通道对象，直接读取其字段
                            if ("外线".equals(node.get("type").asText())) {
                                String status = node.get("status").asText();
//                                if ("通话中".equals(status) || "振铃".equals(status) || "拨号".equals(status)) {
                                if (!"空闲".equals(status)) {
                                    occupied = true;
                                    break;
                                }
                            }
                        }


                    if (occupied) {
                        return "{\"status\":16,\"msg\":\"通道占用\"}";
                    }
                } catch (Exception e) {
                    return "{\"status\":17,\"msg\":\"解析通道状态异常：" + e.getMessage() + "\"}";
                }
            } catch (Exception e) {
                return "{\"status\":17,\"msg\":\"解析通道状态异常：" + e.getMessage() + "\"}";
            }
                } else {
                    System.err.println("登录失败，响应内容不包含frameset。");
                    return "error";
                }
            } catch (IOException e) {
                System.err.println("请求执行失败：" + e.getMessage());
                return "error";
            }
        } catch (IOException e) {
            System.err.println("HttpClient创建失败：" + e.getMessage());
        }
        return "ok";
    }

}